package thinkingInJava.concurrency;
//: concurrency/E27_Restaurant3.java
/********************** Exercise 27 ***********************
 * Modify Restaurant.java to use explicit Lock and Condition
 * objects.
 *********************************************************/
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import static thinkingInJava.YTool.YPrint.*;
class WaitPerson5 implements Runnable {
	private RestaurantT3 restaurant;
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();
	public WaitPerson5(RestaurantT3 r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				lock.lock();
				try {
					while(restaurant.meal == null)
						condition.await();
				} finally {
					lock.unlock();
				}
				print("Waitperson got " + restaurant.meal);
				restaurant.chef.lock.lock();
				try {
					restaurant.meal = null;
					restaurant.chef.condition.signalAll();
				} finally {
					restaurant.chef.lock.unlock();
				}
			}
		} catch(InterruptedException e) {
			print("WaitPerson interrupted");
		}
	}
}
class Chef5 implements Runnable {
	private RestaurantT3 restaurant;
	private int count;
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();
	public Chef5(RestaurantT3 r) { restaurant = r; }
	public void run() {
		try {
			while(!Thread.interrupted()) {
				lock.lock();
				try {
					while(restaurant.meal != null)
						condition.await();
				} finally {
					lock.unlock();
				}
				if(++count == 10) {
					print("Out of food, closing");
					restaurant.exec.shutdownNow();
				}
				printnb("Order up! ");
				restaurant.waitPerson.lock.lock();
				try {
					restaurant.meal = new Meal(count);
					restaurant.waitPerson.condition.signalAll();
				} finally {
					restaurant.waitPerson.lock.unlock();
				}
				TimeUnit.MILLISECONDS.sleep(100);
			}
		} catch(InterruptedException e) {
			print("Chef interrupted");
		}
	}
}
class RestaurantT3 {
	Meal meal;
	ExecutorService exec = Executors.newCachedThreadPool();
	WaitPerson5 waitPerson = new WaitPerson5(this);
	Chef5 chef = new Chef5(this);
	public RestaurantT3() {
		exec.execute(chef);
		exec.execute(waitPerson);
	}
}
public class Restaurant4 {
	public static void main(String[] args) {
		new Restaurant4();
	}
} /* Output: (Sample)
Order up! Waitperson got Meal 1
Order up! Waitperson got Meal 2
Order up! Waitperson got Meal 3
Order up! Waitperson got Meal 4
Order up! Waitperson got Meal 5
Order up! Waitperson got Meal 6
Order up! Waitperson got Meal 7
Order up! Waitperson got Meal 8
Order up! Waitperson got Meal 9
Out of food, closing
Concurrency 643
WaitPerson interrupted
Order up! Chef interrupted
 *///:~
